package cn.virens.common.datasource.annotations.config;

import cn.hutool.core.map.MapUtil;
import cn.virens.common.datasource.annotations.handler.DynamicDataSourceAnnotationSource;
import cn.virens.common.datasource.annotations.handler.DynamicDataSourceMethodInterceptor;
import cn.virens.common.datasource.annotations.handler.DynamicDataSourceMethodPointcutAdvisor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.annotation.Role;
import org.springframework.core.Ordered;
import org.springframework.core.type.AnnotationMetadata;

import java.util.Map;

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class DynamicDataSourceConfiguration implements ImportAware {
    protected int order = Ordered.LOWEST_PRECEDENCE;

    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @Bean("dynamicDataSourceAnnotationSource")
    public DynamicDataSourceAnnotationSource dynamicDataSourceAnnotationSource() throws Exception {
        return new DynamicDataSourceAnnotationSource();
    }

    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @Bean("dynamicDataSourceMethodInterceptor")
    public DynamicDataSourceMethodInterceptor dynamicDataSourceMethodInterceptor() throws Exception {
        DynamicDataSourceMethodInterceptor interceptor = new DynamicDataSourceMethodInterceptor();
        interceptor.setAnnotationSource(dynamicDataSourceAnnotationSource());

        return interceptor;
    }

    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @Bean("dynamicDataSourceMethodPointcutAdvisor")
    public DynamicDataSourceMethodPointcutAdvisor dynamicDataSourceMethodPointcutAdvisor() throws Exception {
        DynamicDataSourceMethodPointcutAdvisor advisor = new DynamicDataSourceMethodPointcutAdvisor();
        advisor.setAnnotationSource(dynamicDataSourceAnnotationSource());
        advisor.setAdvice(dynamicDataSourceMethodInterceptor());
        advisor.setOrder(order);

        return advisor;
    }

    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        Map<String, Object> attributes = getAnnotationAttributes(importMetadata);

        this.order = MapUtil.getInt(attributes, "order", Ordered.LOWEST_PRECEDENCE);
    }

    protected Map<String, Object> getAnnotationAttributes(AnnotationMetadata importMetadata) {
        return importMetadata.getAnnotationAttributes(EnableDynamicDataSource.class.getName(), false);
    }

}
